﻿/*   
    Copyright (C) 2009 Galaktika Corporation ZAO

    This file is a part of Galaktika.BusinessMonitor
 
    Galaktika.BusinessMonitor is a free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
      
    You should have received a copy of the GNU General Public License
    along with Galaktika.BusinessMonitor.  If not, see <http://www.gnu.org/licenses/>.
  
    If GPL v.3 is not suitable for your products or company,
    Galaktika Corp provides Galaktika.BusinessMonitor under a flexible commercial license
    designed to meet your specific usage and distribution requirements.
    If you have already obtained a commercial license from Galaktika Corp,
    you can use this file under those license terms.
*/

using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;

using Ranet.Olap.Core;
using Ranet.Olap.Core.Data;
using Galaktika.BI.Silverlight.Services;
using Galaktika.BI.Silverlight.Commands;
using Galaktika.BI.Runtime.Services;
using Ranet.Olap.Core.Providers;
using Ranet.ZipLib;
//using Ranet.Olap.Core.Compressor;

namespace Galaktika.BI.Silverlight.ClientApp.Web.Runtime.DataAccess
{
    public class OlapQueryExecutor : IQueryExecuter
    {
        internal class SessionHolder
        {
            Dictionary<string, string> m_Sessions = new Dictionary<string, string>();
            public string this[string connectionString]
            {
                get
                {
                    lock (this)
                    {
                        if (m_Sessions.ContainsKey(connectionString))
                        {
                            return m_Sessions[connectionString];
                        }
                    }

                    return null;
                }
                set
                {
                    lock (this)
                    {
                        m_Sessions[connectionString] = value;
                    }
                }
            }
        }

        internal static SessionHolder IdHolder = new SessionHolder();

        private ConnectionInfo m_Connection;
        private IBindingContext m_Context;
        public OlapQueryExecutor(ConnectionInfo connection, IBindingContext context)
        {
            m_Connection = connection;
            m_Context = context;
        }

        #region IQueryExecuter Members

        public ConnectionInfo Connection
        {
            get 
            {
                return m_Connection;
            }
        }

        public CellSetData ExecuteQuery(string query)
        {
            return ExecuteQuery(m_Connection.ConnectionString, query, null, m_Context).Data;
        }

        public int ExecuteNonQuery(string query)
        {
            return ExecuteNonQuery(m_Connection.ConnectionString, null, query).Data;
        }

        #endregion

        internal static QueryResult ExecuteQuery(
            string connectionString, 
            string query, 
            string dataSourceId,
            IBindingContext context)
        {
            string contextId = context != null ? ((IUniquedObject)context).Id : null;
            using (var srv = new SyncDataService())
            {
                if (App.CurrentApp.Binder.UserSettings.Settings.LogMdxQueries)
                {
                    var output = App.CurrentApp.GetService<IOutputService>();
                    if (output != null)
                    {
                        output.WriteLine();
                        output.WriteLine(
                            Localization.Msg_ExecutingMdxCommand,
                            connectionString,
                            IdHolder[connectionString],
                            query);
                    }
                }

                var res = srv.InvokeCommand(CommandBuilder.CreateAdomdCommand(
                    connectionString,
                    query,
                    IdHolder[connectionString],
                    contextId,
                    dataSourceId));
                if (res.ContentType == KnownContentTypes.MultidimData)
                {
                    IdHolder[connectionString] = res.SessionId;
                    string content = res.Content;
                    if (res.IsArchive)
                    {
                        content = ZipCompressor.DecompressFromBase64String(res.Content);
                    }

                    return new QueryResult(CellSetData.Deserialize(content), res);
                    //return XmlUtility.XmlStr2Obj<CellSetData>(res.Content);
                }

                return new QueryResult(res);
            }
        }

        internal static NonQueryResult ExecuteNonQuery(
            string connectionString, 
            string query,
            string dataSourceId)
        {
            //query = ParseStrToXXXCalls(query);
            using (var srv = new SyncDataService())
            {
                if (App.CurrentApp.Binder.UserSettings.Settings.LogMdxQueries)
                {
                    var output = App.CurrentApp.GetService<IOutputService>();
                    if (output != null)
                    {
                        output.WriteLine();
                        output.WriteLine(
                            Localization.Msg_ExecutingMdxCommand,
                            connectionString,
                            IdHolder[connectionString],
                            query);
                    }
                }

                var cmd = CommandBuilder.CreateAdomdCommand(
                    connectionString,
                    query,
                    IdHolder[connectionString],
                    null,
                    dataSourceId);
                cmd.Args.Add(new InvokeArg(KnownInvokeArgs.NonQuery, KnownInvokeArgs.NonQuery));
                var res = srv.InvokeCommand(cmd);
                if (res.ContentType == KnownContentTypes.MultidimData)
                {
                    IdHolder[connectionString] = res.SessionId;
                    if (res.IsArchive)
                    {
                        var unzippedRes = ZipCompressor.DecompressFromBase64String(res.Content);
                        return new NonQueryResult(int.Parse(unzippedRes), res);
                    }

                    return new NonQueryResult(int.Parse(res.Content), res);
                }

                return new NonQueryResult(res);
            }
        }

        //private static string ParseStrToXXXCalls(string input)
        //{
        //    const string pattern = @"(strtoset|strtotuple|strtomember)\('([^']+)'\)";

        //    Regex r = new Regex(pattern, RegexOptions.IgnoreCase);
        //    Match m = r.Match(input);
        //    StringBuilder sb = new StringBuilder();
        //    int startIndex = 0;
        //    while (m.Success)
        //    {
        //        Group entireExp = m.Groups[0];
        //        Group strTo = m.Groups[1];
        //        Group arg = m.Groups[2];

        //        sb.Append(input.Substring(startIndex, strTo.Index - startIndex));
        //        sb.Append(arg.Value);
        //        startIndex = entireExp.Index + entireExp.Length;

        //        m = m.NextMatch();
        //    }

        //    if (input.Length != startIndex)
        //    {
        //        sb.Append(input.Substring(startIndex, input.Length - startIndex));
        //    }

        //    return sb.ToString();
        //}
    }
}
